#pragma once
#include "gtest/gtest.h"
#include "SGFem/ElementCalculator/Factory/ElementCalculatorFactory.h"
#include "DataStructure/Input/Material/ThermalMaterial.h"
#include "DBManager/IService/Input/Node/INodeService.h"
#include "DBManager/IService/Input/Element/IElementService.h"
#include "DBManager/IService/Input/Subcase/ISubcaseService.h"
#include "DBManager/IService/Input/Material/IThermalMaterialService.h"
#include "DBManager/IService/Input/Property/IPSHELLService.h"
#include "../Quad4ThermalCalculator.h"


using SG::Algebra::Matrix;
using SG::DataStructure::Common::Real;
using SG::DataStructure::FEM::ThermalMaterial;
using namespace SG::DataStructure::FEM;
using namespace SG::FEMSolver::Element;

// ElementCalculatorFactory 是否正确创建单元计算类
// 将 ElementCalculatorFactory 的 Register和生成对象测试放置在具体单元类型计算中
TEST (ElementCalculatorFactoryTest, Quad4ThermalElement)
{
    ElementCalculatorFactory::Register (ElementTypes::ELETYPE_ShellQuad4, Quad4ThermalCalculator::Create);

    // Test
    auto CalculatorPtr = ElementCalculatorFactory::Create (ElementTypes::ELETYPE_ShellQuad4);

    // Target data
    auto quad4Calctor = dynamic_cast<Quad4ThermalCalculator*> (CalculatorPtr.get ());

    // Check
    ASSERT_TRUE (0 != quad4Calctor);
}
extern std::shared_ptr<DBServiceFactory> DB_SERVICEFACTORY;

class Quad4ThermalCalculatorTest : public ::testing::Test
{
public:

    virtual void SetUp() override
    {
        DB_SERVICEFACTORY->ClearDatabase ();
        // 指定材料属性
        k  = 1.0;  //热传导系数
        points = SG::Algebra::PointArray(4);
        points[0].m_x = 0;                 points[0].m_y = 0;                  
        points[1].m_x = 2;                 points[1].m_y = 0; 
        points[2].m_x = 2;                 points[2].m_y = 2;  
        points[3].m_x = 0;                 points[3].m_y = 2;  
        
        // 直角坐标系1
        CORD2RData rectangularCoordSys{1, 0, {1.0, 2.0, 3.0}, {2.0, 2.0, 3.0}, {1.0, 3.0, 3.0}};
        DB_SERVICEFACTORY->get<ICORD2RService> ()->Add (rectangularCoordSys);

        // 直角坐标系2
        rectangularCoordSys = {2, 0, {4.0, 2.0, 1.0}, {4.0, 3.0, 1.0}, {4.0, 2.0, 2.0}};
        DB_SERVICEFACTORY->get<ICORD2RService> ()->Add (rectangularCoordSys);

        // 生成节点排序
        auto& assembly = AssemblyEigen::GetInstance ();
        assembly.Clear ();
        Subcase subcase;
        subcase.AddParameter({"SUBCASE","1"});
        assembly.Initialize (DB_SERVICEFACTORY, subcase, {1});

        // 计算坐标系原点和基矢量
        auto& coordProcessor = CoordinateProcessor::GetInstance ();
        coordProcessor.Clear ();
        coordProcessor.Initialize (DB_SERVICEFACTORY);

        CQUAD4Data eleData1{1};
        eleData1.m_pId = 1;
        eleData1.m_g[0] = 2264;
        eleData1.m_g[1] = 2265;
        eleData1.m_g[2] = 2267;
        eleData1.m_g[3] = 2266;
        DB_SERVICEFACTORY ->get<IElementService>()->Add (eleData1);

        CQUAD4Data eleData2{2};
        eleData2.m_pId = 1;
        eleData2.m_g[0] = 2265;
        eleData2.m_g[1] = 2269;
        eleData2.m_g[2] = 2271;
        eleData2.m_g[3] = 2263;
        DB_SERVICEFACTORY ->get<IElementService>()->Add (eleData2);

        NodeData node1{2164};
        node1.m_x[0] = 1.0;
        node1.m_x[1] = 0.1;
        node1.m_x[2] = 0.0;
        DB_SERVICEFACTORY ->get<INodeService>()->Add (node1);
        
        NodeData node2{2175};
        node2.m_x[0] = 1.0;
        node2.m_x[1] = 0.2;
        node2.m_x[2] = 0.0;
        DB_SERVICEFACTORY ->get<INodeService>()->Add (node2);

        NodeData node3{2186};
        node3.m_x[0] = 1.0;
        node3.m_x[1] = 0.3;
        node3.m_x[2] = 0.0;
        DB_SERVICEFACTORY ->get<INodeService>()->Add (node3);

        NodeData node4{2197};
        node4.m_x[0] = 1.0;
        node4.m_x[1] = 0.4;
        node4.m_x[2] = 0.0;
        DB_SERVICEFACTORY ->get<INodeService>()->Add (node4);

        NodeData node5{2208};
        node5.m_x[0] = 1.0;
        node5.m_x[1] = 0.5;
        node5.m_x[2] = 0.0;
        DB_SERVICEFACTORY ->get<INodeService>()->Add (node5);

        NodeData node6{2219};
        node6.m_x[0] = 1.0;
        node6.m_x[1] = 0.6;
        node6.m_x[2] = 0.0;
        DB_SERVICEFACTORY ->get<INodeService>()->Add (node6);

        NodeData node7{2230};
        node7.m_x[0] = 1.0;
        node7.m_x[1] = 0.7;
        node7.m_x[2] = 0.0;
        DB_SERVICEFACTORY ->get<INodeService>()->Add (node7);

        NodeData node8{2241};
        node8.m_x[0] = 1.0;
        node8.m_x[1] = 0.8;
        node8.m_x[2] = 0.0;
        DB_SERVICEFACTORY ->get<INodeService>()->Add (node8);

        NodeData node9{2252};
        node9.m_x[0] = 1.0;
        node9.m_x[1] = 0.9;
        node9.m_x[2] = 0.0;
        DB_SERVICEFACTORY ->get<INodeService>()->Add (node9);

        NodeData node10{2263};
        node10.m_x[0] = 1.0;
        node10.m_x[1] = 1.0;
        node10.m_x[2] = 0.0;
        DB_SERVICEFACTORY ->get<INodeService>()->Add (node10);

        NodeData node11{2264};
        node11.m_x[0] = 0.0;
        node11.m_x[1] = 0.0;
        node11.m_x[2] = 0.0;
        DB_SERVICEFACTORY ->get<INodeService>()->Add (node11);

        NodeData node12{2265};
        node12.m_x[0] = 1.0;
        node12.m_x[1] = 0.0;
        node12.m_x[2] = 0.0;
        DB_SERVICEFACTORY ->get<INodeService>()->Add (node12);

        NodeData node13{2266};
        node13.m_x[0] = 0.0;
        node13.m_x[1] = 2.0;
        node13.m_x[2] = 0.0;
        DB_SERVICEFACTORY ->get<INodeService>()->Add (node13);

        NodeData node14{2267};
        node14.m_x[0] = 1.0;
        node14.m_x[1] = 2.0;
        node14.m_x[2] = 0.0;
        DB_SERVICEFACTORY ->get<INodeService>()->Add (node14);

        NodeData node15{2269};
        node15.m_x[0] = 4.0;
        node15.m_x[1] = 0.0;
        node15.m_x[2] = 0.0;
        DB_SERVICEFACTORY ->get<INodeService>()->Add (node15);

        NodeData node16{2271};
        node16.m_x[0] = 4.0;
        node16.m_x[1] = 1.0;
        node16.m_x[2] = 0.0;
        DB_SERVICEFACTORY ->get<INodeService>()->Add (node16);


        PSHELLData pshellData{1};
        pshellData.m_mId1 = 1;
        pshellData.m_thickness = 1.0;
        DB_SERVICEFACTORY ->get<IPSHELLService>()->Add (pshellData);

        ThermalMaterial material;
        material.m_id = 1;
        material.m_K = 1.0;
        material.m_CP = 1.0;
        material.m_RHO = 1.0;
        DB_SERVICEFACTORY ->get<IThermalMaterialService>()->Add (material);
         
    }

protected:
    Real k;
    SG::Algebra::PointArray points; ///< 单元节点坐标
};

TEST_F (Quad4ThermalCalculatorTest, ComputeStiffness)
{
    Quad4ThermalCalculator elementCalc;
    elementCalc.Initialize(ELETYPE_ShellQuad4);
    Matrix Kel(4, 4);
    Matrix coord(4,2);
    ThermalMaterial material;
    material.m_K = 1.0;
    Real thickness = 1.0;

    for (std::size_t iNode = 0; iNode < 4; ++iNode)
    {
        coord(iNode, 0) = points[iNode].m_x;
        coord(iNode, 1) = points[iNode].m_y;
    }

    elementCalc.ComputeStiffness(coord, material, thickness, Kel);
    
    //待输入
    Matrix KelTarget(4, 4, {          
          0.66666666666667,-0.16666666666667,-0.33333333333333,-0.16666666666667,
          -0.16666666666667, 0.66666666666667,-0.16666666666667,-0.33333333333333,  
          -0.33333333333333, -0.16666666666667, 0.66666666666667,-0.16666666666667,   
          -0.16666666666667, -0.33333333333333, -0.16666666666667, 0.66666666666667
         });
    
    ASSERT_TRUE(Kel == KelTarget);
}

